package com.jiayou.session

import com.jiayou.AuthenticatePackage
import com.jiayou.DefaultProtocolImpl
import com.jiayou.Protocol
import com.jiayou.authention.AuthenticateHandler
import com.jiayou.authention.MessageCondition
import com.jiayou.emnu.FrameType
import com.jiayou.emnu.User
import com.jiayou.ktor
import com.jiayou.tool.*
import io.ktor.network.sockets.*
import io.ktor.utils.io.*
import java.io.Serializable
import java.util.concurrent.ConcurrentHashMap
import kotlin.concurrent.thread

/**
 *  服务端session抽象
 *  T  ->  实际传递数据类型
 *  T1 ->  认证身份类型
 *  T2 ->  认证凭证类型
 */
interface ServerSocketSession<T : Serializable, T1 : Serializable, T2 : Serializable> : MessageCondition<T, T1, T2> {
    var controller: Boolean //开启自定义消息转发 （为true时请重写onMessageCustom）
    var authenticateHandler: AuthenticateHandler<T1, T2>//不为空时则会验证连接请求
    var authenticateTime: Int  //等待验证时间，在指定时间没有发送权限验证包会自动放弃该连接
    var messageAnalysis: ((username: T1, socket: Socket, size: Int, data: ByteArray, protocol: Protocol<T, T1, T2>) -> Unit)?

    //在开启连接的时候回调
    suspend fun onOpen(socket: Socket, authPackPackage: AuthenticatePackage<T, T1, T2>?, readChannel: ByteReadChannel): Boolean {
        val openWriteChannel = socket.openWriteChannel(true)
        val authenticateResult = authenticateHandler.doAuthenticate(authPackPackage!!.username(), authPackPackage.password())
        if (authenticateResult) {
            if (ktor.getUser(authPackPackage.username()) != null) {
                ktor.removeIf { it[User.USERNAME]!! == authPackPackage.username() }
//                val repeatUserByteArray = objectToByteArray(DefaultProtocolImpl<String, String, String>(FrameType.REPEATUSER, null))
//                openWriteChannel.writeInt(repeatUserByteArray.size)
//                openWriteChannel.writeFully(repeatUserByteArray)
//                this.onClash(authPackPackage.username(), socket)
//                return false
            }
            val successByteArray =
                objectToByteArray(DefaultProtocolImpl<String, String, String>(FrameType.AUTHENTICATIONSUCCESS, null))
            openWriteChannel.writeInt(successByteArray.size)
            openWriteChannel.writeFully(successByteArray)
            DefaultServerSocketSession.logger.info("Socket accepted: ${socket.remoteAddress}")
        } else {
            val successByteArray =
                objectToByteArray(DefaultProtocolImpl<String, String, String>(FrameType.AUTHENTICATIONFAILD, null))
            openWriteChannel.writeInt(successByteArray.size)
            openWriteChannel.writeFully(successByteArray)
            thread { socket.close() }
            DefaultServerSocketSession.logger.info("Authenticate failed user by '${authPackPackage.username()}'")
        }
        if (authenticateResult) {
            val user = ConcurrentHashMap<User, Any>()
            user[User.USERNAME] = authPackPackage.username()
            user[User.SOCKET] = socket
            user[User.READ_CHANNEL] = readChannel
            user[User.WRITE_CHANNEL] = openWriteChannel
            ktor.addUser(user)
        }
        return authenticateResult
    }


    //在收到消息的回调， 不自定义转发会默认给连接该服务的所有客户端转发该消息
    suspend fun onMessage(username: T1, socket: Socket, availableLength: Int, byteArray: ByteArray, protocol: Protocol<T, T1, T2>) {
        if (controller) {
            if (messageAnalysis != null) {
                messageAnalysis!!.invoke(username, socket, availableLength, byteArray, protocol)
            } else {
                throw Exception("There are no message analysis handler set!")
            }
        } else {
            sendMessage(byteArray, availableLength, socket)
        }
    }

    //等待连接关闭回调
    suspend fun onWaitClosed(username: T1, socket: Socket) {
        socket.awaitClosed()
        ktor.removeUser(socket)
        DefaultServerSocketSession.logger.info("User $username closed connection")
        thread {
            try {
                if (!socket.isClosed){
                    socket.close()
                }
            }catch (e:java.lang.Exception){
                e.printStackTrace()
            }
        }
    }

    //连接异常回调
    suspend fun onError(username: T1, socket: Socket) {
        ktor.removeUser(socket)
        DefaultServerSocketSession.logger.error("User $username exception connection！")
    }


    //等待消息回调
    suspend fun onWaitMessage(username: T1, socket: Socket): Boolean {
        val readChannel = ktor.getReadChannel(socket)!!
        readChannel.awaitContent()
        if (readChannel.availableForRead == 0) return false
        val availableLength = readChannel.readInt()
        val byteArray = ByteArray(availableLength)
        readChannel.readFully(byteArray, 0, availableLength)
        val protocolData: Protocol<T, T1, T2>? = byteArrayToObject(byteArray)
        if (protocolData != null) {
            this.onMessage(username, socket, availableLength, byteArray, protocolData)
            //如果客户端发来了断开连接的请求这里来断开连接
            if (protocolData.getFrameType() == FrameType.CLOSE) {
                ktor.forEach {
                    if (it[User.SOCKET] == socket) {
                        ktor.removeUser(socket)
                    }
                }
                return false
            }
            return true
        }
        return true
    }


    //放弃本次连接请求？
    suspend fun onClash(username: T1, socket: Socket): Boolean {
        println(username)
        thread {
            try {
                socket.close()
            }catch (e:java.lang.Exception){
                e.printStackTrace()
            }
        }
        return true
    }
}